/*  Ian McBride, John Lokker
 *  CPE 471 lab 6 - draws a house 
 *  glut/OpenGL application which renders a 3D house.  
 *  works in conjunction with a GLSL vertex and fragment shader 
 *
 *  Created by zwood on 1/6/12 
 *  Copyright 2010 Cal Poly. All rights reserved.
 *
 *****************************************************************************/
#ifdef __APPLE__
#include "GLUT/glut.h"
#include <OPENGL/gl.h>
#endif
#ifdef __unix__
#include <GL/glut.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include "GLSL_helper.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp" //perspective, trans etc
#include "glm/gtc/type_ptr.hpp" //value_ptr
#include "RenderingHelper.h"

using namespace std;
using namespace glm;

#define PI 3.14159265
#define TIMER 30

// Macro used to obtain relative offset of a field within a struct
#define FIELD_OFFSET(StructType, field) &(((StructType *)0)->field)

RenderingHelper ModelTrans;

//position and color data handles
GLuint triBuffObj, colBuffObj;

//flag and ID to toggle on and off the shader
int shade = 1;
int ShadeProg;

//Handles to the shader data
GLint h_aPosition;
GLint h_ePosition;
GLint h_aNormal;
GLint h_uModelMatrix;
GLint h_uViewMatrix;
GLint h_uProjMatrix;
GLuint CubeBuffObj, CIndxBuffObj, GrndBuffObj, GIndxBuffObj, GNBuffObj, GNIndxBuffObj, RIndxBuffObj, NormalBuffObj, FenceBuffObj, FIndxBuffObj, FenceNormalBuffObj;
int g_CiboLen, g_GiboLen, g_RiboLen, g_FiboLen;

static float g_width, g_height;
float g_Camtrans = -3.0;
float g_Mtrans = 0;
float g_angle = 0;
float g_Yangle = 0;
static float g_scale = 1;
int g_mat_id =0;
glm::vec3 g_trans(0);

static const float g_groundY = -.51;      // y coordinate of the ground
static const float g_groundSize = 22.0;   // half the ground length
GLint h_uLightPos;
GLint h_uLightColor;
GLint h_uMatAmb, h_uMatDif, h_uMatSpec, h_uMatShine;

float g_timerTrans = 0;
float g_dir = 1;

float moveInc = .05;
float g_xs, g_xe, g_ys, g_ye;

float g_phi = 0;
float g_theta = -PI / 2;

float LAx = cos(g_phi)*cos(g_theta);
float LAy = sin(g_phi);
float LAz = cos(g_phi)*cos(PI/2 - g_theta);

float Eyex = 0;
float Eyey = 0;
float Eyez = 3;

float ux = 1;
float uy = 0;
float uz = 0;

float wx = 0;
float wy = 0;
float wz = 1;

glm::vec3 Eye = glm::vec3(Eyex, Eyey, Eyez);
glm::vec3 LA = glm::vec3(LAx, LAy, LAz);
glm::vec3 g_u = glm::vec3(ux, uy, uz);
glm::vec3 g_v = glm::vec3(0, 1, 0);
glm::vec3 g_w = glm::vec3(wx, wy, wz);

struct BoundingBox
{
    glm::vec3 posn;
    glm::vec3 base;
    glm::vec3 top;
    int type;
    int interactCount;
    bool interacting;
    float angle;
};

float g_gateAng = 0;
int interactingObj = -1;

BoundingBox collide[5000];
int collisionIndex = 0;

/* helper function to set up material for shading */
void SetMaterial(int i) {

  glUseProgram(ShadeProg);
  switch (i) {
    case 0:
        safe_glUniform3f(h_uMatAmb, 0.40, 0.20, 0.20);
        safe_glUniform3f(h_uMatDif, 0.60, 0.40, 0.40);
        safe_glUniform3f(h_uMatSpec, 0.40, 0.30, 0.30);
        safe_glUniform1f(h_uMatShine, 1.0);
        break;
    case 1:
        safe_glUniform3f(h_uMatAmb, 0.20, 0.20, 0.40);
        safe_glUniform3f(h_uMatDif, 0.30, 0.30, 0.40);
        safe_glUniform3f(h_uMatSpec, 0.30, 0.30, 0.40);
        safe_glUniform1f(h_uMatShine, 1.0);
        break;
    case 2:
    /* TO DO fill in another material that is greenish */
          safe_glUniform3f(h_uMatAmb, 0.35, 0.9, 0.25);
          safe_glUniform3f(h_uMatDif, 0.20, 0.85, 0.35);
          safe_glUniform3f(h_uMatSpec, 0.10, 0.95, 0.10);
          safe_glUniform1f(h_uMatShine, 1.0);
        break;
      case 3:
          safe_glUniform3f(h_uMatAmb, 0.25, 0.16, 0.01);
          safe_glUniform3f(h_uMatDif, 0.25, 0.16, 0.01);
          safe_glUniform3f(h_uMatSpec, 0.25, 0.16, 0.01);
          safe_glUniform1f(h_uMatShine, 1.0);
          break;
      case 4:
          safe_glUniform3f(h_uMatAmb, 0.22, 0.28, 0.22);
          safe_glUniform3f(h_uMatDif, 0.22, 0.28, 0.22);
          safe_glUniform3f(h_uMatSpec, 0.22, 0.28, 0.22);
          safe_glUniform1f(h_uMatShine, 1.0);
          break;
      case 5:
          safe_glUniform3f(h_uMatAmb, 0.5, 0.28, 0.22);
          safe_glUniform3f(h_uMatDif, 0.5, 0.28, 0.22);
          safe_glUniform3f(h_uMatSpec, 0.5, 0.28, 0.22);
          safe_glUniform1f(h_uMatShine, 1.0);
          break;
      case 6:
          safe_glUniform3f(h_uMatAmb, 0.44, 0.5, 0.56);
          safe_glUniform3f(h_uMatDif, 0.44, 0.5, 0.56);
          safe_glUniform3f(h_uMatSpec, 0.44, 0.5, 0.56);
          safe_glUniform1f(h_uMatShine, 1.0);
          break;
  }
}

/* set model transforms to the identity*/
void SetModelI() {
  glm::mat4 tmp = glm::mat4(1.0f);
  safe_glUniformMatrix4fv(h_uModelMatrix, glm::value_ptr(tmp));
}

/* projection matrix */
void SetProjectionMatrix() {
  glm::mat4 Projection = glm::perspective(80.0f, (float)g_width/g_height, 0.1f, 100.f);	
  safe_glUniformMatrix4fv(h_uProjMatrix, glm::value_ptr(Projection));
}

/* camera controls */
void SetView() {
    glm::mat4 Trans = glm::translate(glm::mat4(1.0f), -Eye);
    glm::mat4 Rot = glm::lookAt(Eye, LA, glm::vec3(0, 1, 0));
    
    glm::mat4 View = Rot * Trans;

    safe_glUniformMatrix4fv(h_uViewMatrix, glm::value_ptr(View));
}

/* model transforms */
void SetModel() {
    //glm::mat4 Trans = glm::translate( glm::mat4(1.0f), glm::vec3(0, 0, -2));
    //safe_glUniformMatrix4fv(h_uModelMatrix, glm::value_ptr(Trans));
    
    safe_glUniformMatrix4fv(h_uModelMatrix, glm::value_ptr(ModelTrans.modelViewMatrix));
}

static void initGround() {

  // A x-z plane at y = g_groundY of dimension [-g_groundSize, g_groundSize]^2
    float GrndPos[] = { 
    -g_groundSize, g_groundY, -g_groundSize, 
    -g_groundSize, g_groundY,  g_groundSize, 
     g_groundSize, g_groundY,  g_groundSize, 
     g_groundSize, g_groundY, -g_groundSize
    };

    float GrndNorm[] = { 
     0, 1, 0, 
     0, 1, 0, 
     0, 1, 0, 
     0, 1, 0, 
     0, 1, 0, 
     0, 1, 0
    };

    unsigned short idx[] = {0, 1, 2, 0, 2, 3};
    
    g_GiboLen = 6;
    glGenBuffers(1, &GrndBuffObj);
    glBindBuffer(GL_ARRAY_BUFFER, GrndBuffObj);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GrndPos), GrndPos, GL_STATIC_DRAW);

    glGenBuffers(1, &GIndxBuffObj);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GIndxBuffObj);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW);
    
    glGenBuffers(1, &GNBuffObj);
    glBindBuffer(GL_ARRAY_BUFFER, GNBuffObj);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GrndNorm), GrndNorm, GL_STATIC_DRAW);

}

static void initFence() {
    float FencePost[] = {
        0, 0, 0, //back face
        1, 0, 0,
        0, 1, 0,
        1, 1, 0,
        0, 0, 1, //front face
        1, 0, 1,
        0, 1, 1,
        1, 1, 1,
        0, 0, 0, //left face
        0, 0, 1,
        0, 1, 0,
        0, 1, 1,
        1, 0, 0, //right face
        1, 0, 1,
        1, 1, 0,
        1, 1, 1,
        0, 0, 0, //bottom
        1, 0, 0,
        1, 0, 1,
        0, 0, 1,
        0, 1, 0, //top
        0, 1, 1,
        1, 1, 0,
        1, 1, 1
    };
    
    float FenceNormal[] = {
        0, 0, -1,
        0, 0, -1,
        0, 0, -1,
        0, 0, -1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        -1, 0, 0,
        -1, 0, 0,
        -1, 0, 0,
        -1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        0, -1, 0,
        0, -1, 0,
        0, -1, 0,
        0, -1, 0,
        0, 1, 0,
        0, 1, 0,
        0, 1, 0,
        0, 1, 0
    };
    
    unsigned short fenceIdx[] = {0, 1, 3, 0, 2, 3, 4, 5, 7, 4, 6, 7, 8, 9, 11, 8, 10, 11, 12, 13, 15, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 23, 20, 22, 23};
    
    g_FiboLen = 36;
    glGenBuffers(1, &FenceBuffObj);
    glBindBuffer(GL_ARRAY_BUFFER, FenceBuffObj);
    glBufferData(GL_ARRAY_BUFFER, sizeof(FencePost), FencePost, GL_STATIC_DRAW);
    
    glGenBuffers(1, &FenceNormalBuffObj);
    glBindBuffer(GL_ARRAY_BUFFER, FenceNormalBuffObj);
    glBufferData(GL_ARRAY_BUFFER, sizeof(FenceNormal), FenceNormal, GL_STATIC_DRAW);
    
    glGenBuffers(1, &FIndxBuffObj);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, FIndxBuffObj);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(fenceIdx), fenceIdx, GL_STATIC_DRAW);

}

void drawPath(float x, float y, float z, float ang) {
    ModelTrans.pushMatrix();
    ModelTrans.translate(vec3(x, y, z));
    ModelTrans.scale(1, .05, 1);
    SetModel();
    SetMaterial(6);
    glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
}

void drawFence(float x, float y, float z, float ang){
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(x, y, z));
        ModelTrans.scale(.083);
        ModelTrans.rotate(ang, vec3(0, 1, 0));
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(2, 1, .5));
            ModelTrans.scale(10, 1, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(2, 3, .5));
            ModelTrans.scale(10, 1, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(2, 5, .5));
            ModelTrans.scale(10, 1, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(12, 0, 0));
            ModelTrans.scale(2, 7, 2);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.scale(2, 7, 2);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
    SetModel();
    SetMaterial(3);
    glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    
    ModelTrans.popMatrix();
}

void drawGate(float x, float y, float z, float ang) {

/*    switch ((int)ang) {
        case 0:
            collide[interactingObj].top.x = (x / 2) + .7;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) + .2;
            break;
        case 90:
            collide[interactingObj].top.x = (x / 2) + .2;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) - .7;
            break;
        case 180:
            collide[interactingObj].top.x = (x / 2) - .7;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) - .2;
            break;
        case 270:
            collide[interactingObj].top.x = (x / 2) - .2;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) + .7;
            break;
        default: break;
    }
*/    
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(x, y, z));
        ModelTrans.scale(.083);
        ModelTrans.rotate(ang, vec3(0, 1, 0));
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(2, 1, .5));
            ModelTrans.scale(10, 1, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(2, 3, .5));
            ModelTrans.scale(10, 1, 1);
            SetModel();
    SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.rotate(-30, vec3(0, 0, 1));
            ModelTrans.translate(vec3(-4, 7, .5));
            ModelTrans.scale(14, 1, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(2, 5, .5));
            ModelTrans.scale(10, 1, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(12, 1, 0));
            ModelTrans.scale(2, 5, 2);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.scale(2, 9, 2);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        SetModel();
        SetMaterial(3);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
}

void drawTree(float x, float y, float z) {
    
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(x, y, z));
        ModelTrans.scale(.1);
        ModelTrans.pushMatrix();
            ModelTrans.scale(5, 10, 5);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(-6, 8, -6));
            ModelTrans.scale(16);
            SetModel();
            SetMaterial(4);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();            
    
    ModelTrans.popMatrix();
}

void drawChair(float x, float y, float z, float ang) {
    switch ((int)ang) {
        case 0:
            collide[interactingObj].top.x = (x/2) + .25;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z/2) + .25;
            break;
        case 90: 
            collide[interactingObj].top.x = (x / 2) + .25;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) - .25;
            break;
        case 180:
            collide[interactingObj].top.x = (x / 2) - .25;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) - .25;
            break;
        case 270:
            collide[interactingObj].top.x = (x / 2) - .25;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) + .25;
            break;
        default: break;
    }
    
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(x, y, z));
        ModelTrans.scale(.1);
        ModelTrans.rotate(ang, vec3(0, 1, 0));
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(0, 2, 0));
            ModelTrans.scale(4, 4, 1);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.scale(4, 1, 4);
            ModelTrans.translate(vec3(0, 2, 0));
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -3, 0));
                ModelTrans.scale(.2, 3, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -3, 0));
                ModelTrans.scale(.2, 3, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -3, .8));
                ModelTrans.scale(.2, 3, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -3, .8));
                ModelTrans.scale(.2, 3, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.popMatrix();
    ModelTrans.popMatrix();
}

void drawTable(float x, float y, float z, float ang) {
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(x, y, z));
        ModelTrans.scale(.15);
        ModelTrans.rotate(ang, vec3(0, 1, 0));
        ModelTrans.pushMatrix();
            ModelTrans.translate(vec3(0, 2, 0));
            ModelTrans.scale(4, .5, 4);
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -3, 0));
                ModelTrans.scale(.2, 4, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -3, 0));
                ModelTrans.scale(.2, 4, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -3, .8));
                ModelTrans.scale(.2, 4, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -3, .8));
                ModelTrans.scale(.2, 4, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
        ModelTrans.popMatrix();
    ModelTrans.popMatrix();
}

void drawBed(float x, float y, float z, float ang) {
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(x, y, z));
        ModelTrans.scale(.6);
        ModelTrans.rotate(ang, vec3(0, 1, 0));
        ModelTrans.scale(.5, .25, .4);
        ModelTrans.pushMatrix();
            ModelTrans.scale(.3);
            ModelTrans.scale(6, 4, 16);
            ModelTrans.translate(vec3(-.25, -.2, 0));
            SetModel();
            SetMaterial(4);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.scale(.3);
            ModelTrans.scale(6, 2, 16);
            ModelTrans.translate(vec3(-.25, -1.2, 0));
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -.5, 0));
                ModelTrans.scale(.2, .5, .1);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -.5, 0));
                ModelTrans.scale(.2, .5, .1);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -.5, .9));
                ModelTrans.scale(.2, .5, .1);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -.5, .9));
                ModelTrans.scale(.2, .5, .1);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
                ModelTrans.scale(.3);
                ModelTrans.scale(7, 14, 1);
                ModelTrans.translate(vec3(-.3, -.25, -.2));
                SetModel();
                SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
        ModelTrans.pushMatrix();
            ModelTrans.scale(.3);
            ModelTrans.scale(7, 8, 1);
            ModelTrans.translate(vec3(-.3, -.4, 15.5));
            SetModel();
            SetMaterial(3);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
        ModelTrans.popMatrix();
    SetModel();
    SetMaterial(1);
    glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    
    ModelTrans.popMatrix();
}

void drawCow(float x, float y, float z, float ang) {
    ModelTrans.pushMatrix();
    ModelTrans.translate(vec3(x, y, z + g_timerTrans));
    ModelTrans.scale(.5);
    ModelTrans.rotate(180 * g_dir, vec3(0, 1, 0));
    ModelTrans.translate(vec3(0, .9, 0));
    ModelTrans.scale(.5);
        ModelTrans.pushMatrix();
            ModelTrans.scale(.3);
            ModelTrans.scale(6, 6, 9);
            ModelTrans.translate(vec3(-.2, -.9, .2));
            SetModel();
            SetMaterial(6);
            glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -.7, 0));
                ModelTrans.scale(.2, .7, .2);
                SetModel();
                SetMaterial(6);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -.7, 0));
                ModelTrans.scale(.2, .7, .2);
                SetModel();
                SetMaterial(3);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(0, -.7, .8));
                ModelTrans.scale(.2, .7, .2);
                SetModel();
                SetMaterial(6);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
            ModelTrans.pushMatrix();
                ModelTrans.translate(vec3(.8, -.7, .8));
                ModelTrans.scale(.2, .7, .2);
                SetModel();
                SetMaterial(6);
                glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
            ModelTrans.popMatrix();
        ModelTrans.popMatrix();
    SetModel();
    SetMaterial(3);
    glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    
    ModelTrans.popMatrix();
}

void drawHouse(float x, float y, float z, float ang) {
    ModelTrans.pushMatrix();
    ModelTrans.translate(vec3(x, y, z));
    ModelTrans.scale(.25);
    ModelTrans.rotate(ang, vec3(0, 1, 0));
    ModelTrans.pushMatrix();
    //back
        ModelTrans.translate(vec3(0, 5, 0));
        ModelTrans.scale(12, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 0, 0));
        ModelTrans.scale(12, 3, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 3, 0));
        ModelTrans.scale(2, 2, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(5, 3, 0));
        ModelTrans.scale(2, 2, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(10, 3, 0));
        ModelTrans.scale(2, 2, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //left
        ModelTrans.translate(vec3(0, 0, 0));
        ModelTrans.scale(.5, 10, 12);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //right
        ModelTrans.translate(vec3(11.5, 0, 0));
        ModelTrans.scale(.5, 10, 12);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //front
        ModelTrans.translate(vec3(0, 5, 12));
        ModelTrans.scale(12, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 0, 12));
        ModelTrans.scale(5, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(7, 0, 12));
        ModelTrans.scale(5, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //floor
        ModelTrans.translate(vec3(0, 0, .05));
        ModelTrans.scale(12, .2, 12);
        SetModel();
        SetMaterial(1);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //ceiling
        ModelTrans.translate(vec3(0, 9.5, 0));
        ModelTrans.scale(12, .5, 12);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    
    ModelTrans.popMatrix();
}

void drawInn(float x, float y, float z, float ang) {
    ModelTrans.pushMatrix();
    ModelTrans.translate(vec3(x, y, z));
    ModelTrans.scale(.25);
    ModelTrans.rotate(ang, vec3(0, 1, 0));
    ModelTrans.pushMatrix();
        //back
        ModelTrans.translate(vec3(0, 5, 20));
        ModelTrans.scale(24, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 0, 20));
        ModelTrans.scale(24, 3, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 3, 20));
        ModelTrans.scale(6, 2, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(9, 3, 20));
        ModelTrans.scale(6, 2, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(18, 3, 20));
        ModelTrans.scale(6, 2, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //left
        ModelTrans.translate(vec3(0, 0, 0));
        ModelTrans.scale(.5, 10, 20);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //right
        ModelTrans.translate(vec3(23.5, 0, 0));
        ModelTrans.scale(.5, 10, 20);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //front
        ModelTrans.translate(vec3(0, 5, 0));
        ModelTrans.scale(24, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 0, 0));
        ModelTrans.scale(5, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(9, 0, 0));
        ModelTrans.scale(15, 5, .5);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //floor
        ModelTrans.translate(vec3(0, 0, .05));
        ModelTrans.scale(24, .2, 20);
        SetModel();
        SetMaterial(1);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
    //ceiling
        ModelTrans.translate(vec3(0, 9.5, 0));
        ModelTrans.scale(24, .5, 20);
        SetModel();
        SetMaterial(5);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    
    ModelTrans.popMatrix();
}

void drawDoor(float x, float y, float z, float ang) {
/*    switch ((int)ang) {
        case 0:
            collide[interactingObj].top.x = (x/2) + .25;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z/2) + .1;
            break;
        case 90: 
            collide[interactingObj].top.x = (x / 2) + .1;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) - .25;
            break;
        case 180:
            collide[interactingObj].top.x = (x / 2) - .25;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) - .1;
            break;
        case 270:
            collide[interactingObj].top.x = (x / 2) - .1;
            collide[interactingObj].top.y = y + .5;
            collide[interactingObj].top.z = (z / 2) + .25;
            break;
        default: break;
    }
*/    
//    printf("Base: %f, %f, %f\n", collide[interactingObj].base.x, collide[interactingObj].base.y, collide[interactingObj].base.z);
//    printf("Top: %f, %f, %f\n", collide[interactingObj].top.x, collide[interactingObj].top.y, collide[interactingObj].top.z);

    ModelTrans.pushMatrix();
    ModelTrans.translate(vec3(x, y, z));
    ModelTrans.scale(.25);
    ModelTrans.rotate(ang, vec3(0, 1, 0));
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 0, 0));
        ModelTrans.scale(2, 3, .25);
        SetModel();
        SetMaterial(3);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 4, 0));
        ModelTrans.scale(2, 1, .25);
        SetModel();
        SetMaterial(3);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(0, 3, 0));
        ModelTrans.scale(.5, 1, .25);
        SetModel();
        SetMaterial(3);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(1.5, 3, 0));
        ModelTrans.scale(.5, 1, .25);
        SetModel();
        SetMaterial(3);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(1, 3, .1));
        ModelTrans.scale(.1, 1, .1);
        SetModel();
        SetMaterial(4);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    ModelTrans.pushMatrix();
        ModelTrans.translate(vec3(.5, 3.5, .1));
        ModelTrans.scale(1, .1, .1);
        SetModel();
        SetMaterial(4);
        glDrawElements(GL_TRIANGLES, g_FiboLen, GL_UNSIGNED_SHORT, 0);
    ModelTrans.popMatrix();
    
    ModelTrans.popMatrix();
}

void drawCenterTrees() {
  drawTree(-6, -.5, -8);
  drawTree(-4, -.5, -8);
  drawTree(0, -.5, -8);
  drawTree(2, -.5, -8);
  drawTree(-6, -.5, -6);
  drawTree(2, -.5, -4);
  drawTree(-6, -.5, -2);
  drawTree(-4, -.5, -2);
  drawTree(0, -.5, -2);
  drawTree(2, -.5, -2);
}

void initDoorInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    collide[collisionIndex].interactCount = 0;
    collide[collisionIndex].interacting = false;
    collide[collisionIndex].type = 0;
    collide[collisionIndex].angle = ang;
    
    //printf("%f, %f, %f\n", collide[collisionIndex].base.x, collide[collisionIndex].base.y, collide[collisionIndex].base.z);
    
    switch ((int)ang) {
        case 0:
            collide[collisionIndex].top.x = (x / 2) + .25;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) + .1;
            break;
        case 90: 
            collide[collisionIndex].top.x = (x / 2) + .1;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) - .25;
            break;
        case 180:
            collide[collisionIndex].top.x = (x / 2) - .25;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) - .1;
            break;
        case 270:
            collide[collisionIndex].top.x = (x / 2) - .1;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) + .25;
            break;
        default: break;
    }
    
    //printf("%f, %f, %f\n", collide[collisionIndex].top.x, collide[collisionIndex].top.y, collide[collisionIndex].top.z);
    
    collisionIndex++;
printf("%f, %f, %f\n", x, y, z);
    drawDoor(x, y, z, ang);
}

void initFenceInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    collide[collisionIndex].base.x = x / 2;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = z / 2;
    collide[collisionIndex].interactCount = 0;
    collide[collisionIndex].interacting = false;
    collide[collisionIndex].type = 2;
    collide[collisionIndex].angle = ang;

    if(ang == 0) {
        collide[collisionIndex].top.x = (x / 2) + .7;
        collide[collisionIndex].top.y = y + .5;
        collide[collisionIndex].top.z = (z / 2) + .2;
    } else if(ang == 90) {
        collide[collisionIndex].top.x = (x / 2) + .2;
        collide[collisionIndex].top.y = y + .5;
        collide[collisionIndex].top.z = (z / 2) - .7;
    }
    collisionIndex++;
    drawFence(x, y, z, ang);
}

void initTreeInWorld(float x, float y, float z) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;

    collide[collisionIndex].base.x = x / 2;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = z / 2;

    collide[collisionIndex].top.x = (x / 2) + .3;
    collide[collisionIndex].top.y = y + .8;
    collide[collisionIndex].top.z = (z / 2) + .3;
    collide[collisionIndex].interactCount = 0;
    collide[collisionIndex].interacting = false;
    collide[collisionIndex].type = 3;

    collisionIndex++;
    drawTree(x, y, z);
}

void initGateInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;

    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    collide[collisionIndex].interactCount = 0;
    collide[collisionIndex].interacting = false;
    collide[collisionIndex].type = 1;
    collide[collisionIndex].angle = ang;

    //printf("%f, %f, %f\n", collide[collisionIndex].base.x, collide[collisionIndex].base.y, collide[collisionIndex].base.z);
    switch ((int)ang) {
        case 0:
            collide[collisionIndex].top.x = (x / 2) + .7;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) + .2;
            break;
        case 90: 
            collide[collisionIndex].top.x = (x / 2) + .2;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) - .7;
            break;
        case 180:
            collide[collisionIndex].top.x = (x / 2) - .7;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) - .2;
            break;
        case 270:
            collide[collisionIndex].top.x = (x / 2) - .2;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) + .7;
            break;
        default: break;
    }
    
    //printf("%f, %f, %f\n", collide[collisionIndex].top.x, collide[collisionIndex].top.y, collide[collisionIndex].top.z);

    collisionIndex++;
    drawGate(x, y, z, ang);
}

void initBedInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;

    collide[collisionIndex].base.x = (x / 2) - .15;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2) - .1;

    collide[collisionIndex].top.x = (x / 2) + .25;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + .5;

    collide[collisionIndex].type = 6;
    collide[collisionIndex].angle = ang;

    collisionIndex++;
    drawBed(x, y, z, ang);
}

void initTableInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + .35;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + .35;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 8;
    
    collisionIndex++;
    drawTable(x, y, z, ang);
}

void initChairInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    switch ((int)ang) {
        case 0:
            collide[collisionIndex].top.x = (x / 2) + .25;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) + .25;
            break;
        case 90: 
            collide[collisionIndex].top.x = (x / 2) + .25;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) - .25;
            break;
        case 180:
            collide[collisionIndex].top.x = (x / 2) - .25;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) - .25;
            break;
        case 270:
            collide[collisionIndex].top.x = (x / 2) - .25;
            collide[collisionIndex].top.y = y + .5;
            collide[collisionIndex].top.z = (z / 2) + .25;
            break;
        default: break;
    }

    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 5;

    collisionIndex++;
    drawChair(x, y, z, ang);
}

void initCowInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + .35;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + .35;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 4;
    
    collisionIndex++;
    drawCow(x, y, z, ang);
}

void initInnInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + .625;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + .15;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 9;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2) + 1.2;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + 3;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + .15;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + .15;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 2.5;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2) + 3;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + 3.15;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 2.5;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2) + 2.5;
    
    collide[collisionIndex].top.x = (x / 2) + 3;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 2.65;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    drawInn(x, y, z, ang);
}

void initHouseInWorld(float x, float y, float z, float ang) {
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + 1.5;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + .15;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 7;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + .15;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 1.6;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2) + 1.5;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2);
    
    collide[collisionIndex].top.x = (x / 2) + 1.65;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 1.6;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2);
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2) + 1.5;
    
    collide[collisionIndex].top.x = (x / 2) + .625;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 1.65;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    
    collide[collisionIndex].posn.x = x;
    collide[collisionIndex].posn.y = y;
    collide[collisionIndex].posn.z = z;
    
    collide[collisionIndex].base.x = (x / 2) + .875;
    collide[collisionIndex].base.y = y;
    collide[collisionIndex].base.z = (z / 2) + 1.5;
    
    collide[collisionIndex].top.x = (x / 2) + 1.5;
    collide[collisionIndex].top.y = y + .5;
    collide[collisionIndex].top.z = (z / 2) + 1.65;
    
    collide[collisionIndex].angle = ang;
    collide[collisionIndex].type = 20;
    
    collisionIndex++;
    drawHouse(x, y, z, ang);
}

void initWorld() {
    ModelTrans.useModelViewMatrix();

    //initDoorInWorld(0, -.5, 0, 0);

    //Boundaries
    for(int i = -20; i < 20; i++) {
        initFenceInWorld(i, -.5, -20, 0);
        initTreeInWorld(i, -.5, -20.5);
    }
    for(int i = -20; i < 20; i++) {
        initFenceInWorld(i, -.5, 20, 0);
        initTreeInWorld(i, -.5, 20.5);
    }
    for(int i = -19; i <= 20; i++) {
        initFenceInWorld(-20, -.5, i + .17, 90);
        initTreeInWorld(-20.5, -.5, i - 1);
    }
    for(int i = -19; i <= 20; i++) {
        initFenceInWorld(20, -.5, i + .17, 90);
        initTreeInWorld(20.5, -.5, i - 1);
    }

    //orchard
    for(int i = -18; i < -8; i+=2) {
      for(int j = -18; j < -8; j+=2) {
        initTreeInWorld(i, -.5, j);
      }
    }

    //Orchard Fence
    for(int i = -20; i < -8; i++) {
      initFenceInWorld(i, -.5, -8, 0);
      if(i == -18) {
        initGateInWorld(-8, -.5, i + 1.17, 90);
      } else {
        initFenceInWorld(-8, -.5, i + 1.17, 90);
      }
    }
    
    //left houses
    initHouseInWorld(-16, -.5, -4, 0);
    initDoorInWorld(-16 + 1.25, -.5, -4 + 3, 0);
    initBedInWorld(-16 + .25, -.3, -4 + .25, 0);
    initTableInWorld(-16 + 1.25, -.5, -4 + 1.25, 0);
    initChairInWorld(-16 + 1.25, -.5, -4 + 1, 0);
    
    initHouseInWorld(-16, -.5, 4, 0);
    initDoorInWorld(-16 + 1.25, -.5, 4 + 3, 0);
    initBedInWorld(-16 + .25, -.3, 4 + .25, 0);
    initTableInWorld(-16 + 1.25, -.5, 4 + 1.25, 0);
    initChairInWorld(-16 + 1.25, -.5, 4 + 1, 0);
    
    initHouseInWorld(-16, -.5, 12, 0);
    initDoorInWorld(-16 + 1.25, -.5, 12 + 3, 0);
    initBedInWorld(-16 + .25, -.3, 12 + .25, 0);
    initTableInWorld(-16 + 1.25, -.5, 12 + 1.25, 0);
    initChairInWorld(-16 + 1.25, -.5, 12 + 1, 0);
    
    //back houses
    initHouseInWorld(-2, -.5, -16, 0);
    initDoorInWorld(-2 + 1.25, -.5, -16 + 3, 0);
    initBedInWorld(-2 + .25, -.3, -16 + .25, 0);
    initTableInWorld(-2 + 1.25, -.5, -16 + 1.25, 0);
    initChairInWorld(-2 + 1.25, -.5, -16 + 1, 0);
    
    for (int i = 1; i < 10; i++) {
        if(i == 5) {
            initGateInWorld(i, -.5, -13, 0);
        }
        else {
            initFenceInWorld(i, -.5, -13, 0);
        }
    }
    for(int i = -20; i < -16; i++) {
        initFenceInWorld(1, -.5, i + 1.17, 90);
    }
    for(int i = -20; i < -16; i++) {
        initFenceInWorld(10, -.5, i + 1.17, 90);
    }
    initCowInWorld(3, -.3, -18, 0);
    initCowInWorld(7, -.3, -18, 0);
    
    initHouseInWorld(10, -.5, -16, 0);
    initDoorInWorld(10 + 1.25, -.5, -16 + 3, 0);
    initBedInWorld(10 + .25, -.3, -16 + .25, 0);
    initTableInWorld(10 + 1.25, -.5, -16 + 1.25, 0);
    initChairInWorld(10 + 1.25, -.5, -16 + 1, 0);

    //right house
    initHouseInWorld(10, -.5, 0, 0);
    initDoorInWorld(10 + 1.25, -.5, 0 + 3, 0);
    initBedInWorld(10 + .25, -.3, 0 + .25, 0);
    initTableInWorld(10 + 1.25, -.5, 0 + 1.25, 0);
    initChairInWorld(10 + 1.25, -.5, 0 + 1, 0);
    
    for (int i = -10; i < 0; i++) {
        initFenceInWorld(10.01, -.5, i + 1.17, 90);
    }
    for (int i = 10; i < 20; i++) {
        initFenceInWorld(i, -.5, -10, 0);
    }
    for (int i = 13; i < 20; i++) {
        initFenceInWorld(i, -.5, 0, 0);
    }
    initCowInWorld(13, -.3, -8, 0);
    initCowInWorld(16, -.3, -6, 0);
    
    //inn
    initInnInWorld(6, -.5, 8, 0);
    initTableInWorld(6 + 1, -.5, 8 + 4, 0);
    initChairInWorld(6 + .5, -.5, 8 + 4.5, 90);
    initChairInWorld(6 + 2.1, -.5, 8 + 4, 270);
    
    initTableInWorld(6 + 1, -.5, 8 + 2, 0);
    initChairInWorld(6 + .5, -.5, 8 + 2.5, 90);
    initChairInWorld(6 + 2.1, -.5, 8 + 2, 270);
    
    initTableInWorld(6 + 3, -.5, 8 + 4, 0);
    initChairInWorld(6 + 2.5, -.5, 8 + 4.5, 90);
    initChairInWorld(6 + 4.1, -.5, 8 + 4, 270);
    
    initTableInWorld(6 + 3, -.5, 8 + 2, 0);
    initChairInWorld(6 + 2.5, -.5, 8 + 2.5, 90);
    initChairInWorld(6 + 4.1, -.5, 8 + 2, 270);
    
    //center trees
    initTreeInWorld(-6, -.5, -8);
    initTreeInWorld(-4, -.5, -8);
    initTreeInWorld(0, -.5, -8);
    initTreeInWorld(2, -.5, -8);
    initTreeInWorld(-6, -.5, -6);
    initTreeInWorld(2, -.5, -4);
    initTreeInWorld(-6, -.5, -2);
    initTreeInWorld(-4, -.5, -2);
    initTreeInWorld(0, -.5, -2);
    initTreeInWorld(2, -.5, -2);
    
    
    //initBedInWorld(-6, -.4, 10, 0);
    //initChairInWorld(-6, -.5, 8, 0);
    //initTableInWorld(-4, -.5, 8, 0);
    //initCowInWorld(-3, 0, 8, 0);
    //initDoorInWorld(6 + 1.25, -.5, 12 + 3, 0);
}

void InitGeom() {
  initGround();
  initFence();
  initWorld();
}

/*function to help load the shaders (both vertex and fragment */
int InstallShader(const GLchar *vShaderName, const GLchar *fShaderName) {
        GLuint VS; //handles to shader object
        GLuint FS; //handles to frag shader object
        GLint vCompiled, fCompiled, linked; //status of shader

        VS = glCreateShader(GL_VERTEX_SHADER);
        FS = glCreateShader(GL_FRAGMENT_SHADER);

        //load the source
        glShaderSource(VS, 1, &vShaderName, NULL);
        glShaderSource(FS, 1, &fShaderName, NULL);

        //compile shader and print log
        glCompileShader(VS);
        /* check shader status requires helper functions */
        printOpenGLError();
        glGetShaderiv(VS, GL_COMPILE_STATUS, &vCompiled);
        printShaderInfoLog(VS);

        //compile shader and print log
        glCompileShader(FS);
        /* check shader status requires helper functions */
        printOpenGLError();
        glGetShaderiv(FS, GL_COMPILE_STATUS, &fCompiled);
        printShaderInfoLog(FS);

        if (!vCompiled || !fCompiled) {
                printf("Error compiling either shader %s or %s", vShaderName, fShaderName);
                return 0;
        }

        //create a program object and attach the compiled shader
        ShadeProg = glCreateProgram();
        glAttachShader(ShadeProg, VS);
        glAttachShader(ShadeProg, FS);

        glLinkProgram(ShadeProg);
        /* check shader status requires helper functions */
        printOpenGLError();
        glGetProgramiv(ShadeProg, GL_LINK_STATUS, &linked);
        printProgramInfoLog(ShadeProg);

        glUseProgram(ShadeProg);

        /* get handles to attribute data */
        h_ePosition = safe_glGetAttribLocation(ShadeProg, "ePosition");
        h_aPosition = safe_glGetAttribLocation(ShadeProg, "aPosition");
        h_aNormal = safe_glGetAttribLocation(ShadeProg, "aNormal");
        h_uProjMatrix = safe_glGetUniformLocation(ShadeProg, "uProjMatrix");
        h_uViewMatrix = safe_glGetUniformLocation(ShadeProg, "uViewMatrix");
        h_uModelMatrix = safe_glGetUniformLocation(ShadeProg, "uModelMatrix");
        h_uLightPos = safe_glGetUniformLocation(ShadeProg, "uLightPos");
        h_uLightColor = safe_glGetUniformLocation(ShadeProg, "uLColor");
        h_uMatAmb = safe_glGetUniformLocation(ShadeProg, "uMat.aColor");
        h_uMatDif = safe_glGetUniformLocation(ShadeProg, "uMat.dColor");
        h_uMatSpec = safe_glGetUniformLocation(ShadeProg, "uMat.sColor");
        h_uMatShine = safe_glGetUniformLocation(ShadeProg, "uMat.shine");

        printf("sucessfully installed shader %d\n", ShadeProg);
        return 1;
	
}


/* Some OpenGL initialization */
void Initialize ()					// Any GL Init Code 
{
	// Start Of User Initialization
	glClearColor (1.0f, 1.0f, 1.0f, 1.0f);								
	// Black Background
 	glClearDepth (1.0f);	// Depth Buffer Setup
 	glDepthFunc (GL_LEQUAL);	// The Type Of Depth Testing
	glEnable (GL_DEPTH_TEST);// Enable Depth Testing
}

/* Main display function */
void Draw (void)
{    
	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);				
	//Start our shader	
 	glUseProgram(ShadeProg);
    SetProjectionMatrix();
    SetView();
    /* TO DO set up the light's position and color */
    
    safe_glUniform3f(h_ePosition, Eye.x, Eye.y, Eye.z);   
    safe_glUniform3f(h_uLightColor, 1.0, 1.0, 1.0);
    safe_glUniform3f(h_uLightPos, 20.0, 10.0, 20.0);

	//actually draw the ground plane data
    SetModelI();
    SetMaterial(2);
	safe_glEnableVertexAttribArray(h_aPosition);
    glBindBuffer(GL_ARRAY_BUFFER, GrndBuffObj);
    safe_glVertexAttribPointer(h_aPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
    
    safe_glEnableVertexAttribArray(h_aNormal);
    glBindBuffer(GL_ARRAY_BUFFER, GNBuffObj);
    safe_glVertexAttribPointer(h_aNormal, 3, GL_FLOAT, GL_FALSE, 0, 0);

    // draw!
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GIndxBuffObj);
    glDrawElements(GL_TRIANGLES, g_GiboLen, GL_UNSIGNED_SHORT, 0);

    // Disable the attributes used by our shader
    safe_glDisableVertexAttribArray(h_aPosition);
    safe_glDisableVertexAttribArray(h_aNormal);

    /* Get ready to draw the house */
    SetModel();
    SetMaterial(0);
	safe_glEnableVertexAttribArray(h_aPosition);
    glBindBuffer(GL_ARRAY_BUFFER, CubeBuffObj);
    safe_glVertexAttribPointer(h_aPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);

	safe_glEnableVertexAttribArray(h_aNormal);
    glBindBuffer(GL_ARRAY_BUFFER, NormalBuffObj);
    safe_glVertexAttribPointer(h_aNormal, 3, GL_FLOAT, GL_FALSE, 0, 0);

   	// draw!
   	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, CIndxBuffObj);
   	glDrawElements(GL_TRIANGLES, g_CiboLen, GL_UNSIGNED_SHORT, 0);

    SetMaterial(1);
    /* now draw the roofs */
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RIndxBuffObj);
    glDrawElements(GL_TRIANGLES, g_RiboLen, GL_UNSIGNED_SHORT, 0);

    // Disable the attributes used by our shader
    safe_glDisableVertexAttribArray(h_aPosition);
    safe_glDisableVertexAttribArray(h_aNormal);
    
    //DRAW THE FENCE
    SetModelI();
    safe_glEnableVertexAttribArray(h_aPosition);
    glBindBuffer(GL_ARRAY_BUFFER, FenceBuffObj);
    safe_glVertexAttribPointer(h_aPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
    
	safe_glEnableVertexAttribArray(h_aNormal);
    glBindBuffer(GL_ARRAY_BUFFER, FenceNormalBuffObj);
    safe_glVertexAttribPointer(h_aNormal, 3, GL_FLOAT, GL_FALSE, 0, 0);
    
    //bind ibo
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, FIndxBuffObj);
    ModelTrans.useModelViewMatrix();
 
    for(int i = 0; i < collisionIndex; i++) {
      switch (collide[i].type) {
        case 0: drawDoor(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 1: drawGate(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 2: drawFence(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 3: drawTree(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z);
                break;
        case 4: drawCow(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 5: drawChair(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 6: drawBed(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 7: drawHouse(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 8: drawTable(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
                break;
        case 9: drawInn(collide[i].posn.x, collide[i].posn.y, collide[i].posn.z, collide[i].angle);
              break;
        default: break;
      }
    }
    
    //paths
    for(int i = -15; i < 8; i++) {
        drawPath(i, -.5, -.5, 0);
    }
    for(int i = 0; i < 16; i++) {
        drawPath(-12, -.5, i, 0);
    }
    for(int i = -15; i < -11; i++) {
        drawPath(i, -.5, 7.5, 0);
        drawPath(i, -.5, 15.5, 0);
    }
    for(int i = -12; i < 8; i++) {
        drawPath(7.25, -.5, i, 0);
    }
    for(int i = -7; i < 12; i++) {
        drawPath(i, -.5, -12, 0);
    }
    for(int i = -18; i < -12; i++) {
        drawPath(-7, -.5, i, 0);
    }
    for(int i = 8; i < 12; i++) {
        drawPath(i, -.5, 3.5, 0);
    }
    

    // Disable the attributes used by our shader
    safe_glDisableVertexAttribArray(h_aPosition);
    safe_glDisableVertexAttribArray(h_aNormal);

	//Disable the shader
	glUseProgram(0);	
	glutSwapBuffers();

}

/* Reshape */
void ReshapeGL (int width, int height)								
{
	g_width = (float)width;
	g_height = (float)height;
	glViewport (0, 0, (GLsizei)(width), (GLsizei)(height));				

}

void mouse(int button, int state, int x, int y) {
    if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
        g_xs = x;
        g_ys = y;
    }
}

void mouseMove(int x, int y) {
    g_xe = x;
    g_ye = y;
    
    g_phi += ((g_ye - g_ys) * 1.0 / g_height) * PI;
    g_theta += ((g_xe - g_xs) * 1.0 / g_width) * PI;
    
    //1.55radians ~ 88-89 degrees
    if(g_phi > 1.55) {
        g_phi = 1.55;
    }
    else if (g_phi < -1.55) {
        g_phi = -1.55;
    }
    
    LAx = cos(g_phi)*cos(g_theta) + Eyex;
    LAy = sin(g_phi) + Eyey;
    LAz = cos(g_phi)*cos(PI/2 - g_theta) + Eyez;
    
    LA = glm::vec3(LAx, LAy, LAz);
    
    g_w = -(glm::normalize(LA - Eye));
    g_u = glm::normalize(glm::cross(glm::vec3(0, 1, 0), g_w));
    g_v = glm::cross(g_w, g_u);
    
    wx = g_w.x;
    wy = g_w.y;
    wz = g_w.z;
    
    ux = g_u.x;
    uy = g_u.y;
    uz = g_u.z;
    
    glutPostRedisplay(); 
    
    g_xs = g_xe;
    g_ys = g_ye;
}

int willCollide(float x, float y, float z) {
    printf("Move pos: x=%f y=%f z=%f\n", x, y, z);
  for(int i = 0; i < collisionIndex; i++) {
    float minx = std::min(collide[i].base.x, collide[i].top.x);
    float maxx = std::max(collide[i].base.x, collide[i].top.x);
    float miny = std::min(collide[i].base.y, collide[i].top.y);
    float maxy = std::max(collide[i].base.y, collide[i].top.y);
    float minz = std::min(collide[i].base.z, collide[i].top.z);
    float maxz = std::max(collide[i].base.z, collide[i].top.z);
      
    if (x >= minx && x <= maxx && y >= miny && y <= maxy && z >= minz && z <= maxz) {
printf("Colliding with %d bot - %f, %f, %f; top - %f, %f, %f\n", i, collide[i].base.x, collide[i].base.y, collide[i].base.z, collide[i].top.x, collide[i].top.y, collide[i].top.z);
      if(collide[i].type >= 2) {
        return -2;
      } else {
        if(collide[i].interacting == false) {
          return i;
        } else {
          return -1;
        }
      }
    }
  }
    return -1;
}

static void interact(int value) {
printf("%d, %d, %d\n", interactingObj, collide[interactingObj].interacting, value);
if(interactingObj != -1) {
  if(collide[interactingObj].interacting == 0) {
    collide[interactingObj].interacting = 1;
    collide[interactingObj].interactCount++;
  }

  if(value >= 0 && value < 45){
    //g_gateAng = value * 2;    
    
    collide[interactingObj].angle = collide[interactingObj].angle + 2;
    Draw();
    glutTimerFunc(TIMER, interact, value + 1);
  } else if(value >= 45 && value < 225) {
    Draw();
    glutTimerFunc(TIMER, interact, value + 1);
  } else if(value >= 225 && value < 270) {
    //g_gateAng = (270 - value * 2);    
    
    collide[interactingObj].angle = collide[interactingObj].angle - 2;
    Draw();
    glutTimerFunc(TIMER, interact, value + 1);
  } else {
    collide[interactingObj].interacting = 0;
    interactingObj = -1;
    Draw();
  }
}
  
}

//the keyboard callback
void keyboard(unsigned char key, int x, int y ){
  int col = -1;
  switch( key ) {
    case 'w':
      col = willCollide(Eyex - moveInc * wx, Eyey, Eyez - moveInc * wz);
      if(col == -1){
          Eyex -= moveInc * (wx);
          Eyez -= moveInc * (wz);
          LAx -= moveInc * (wx);
          LAz -= moveInc * (wz);
          Eye = glm::vec3(Eyex, 0, Eyez);
          LA = glm::vec3(LAx, LAy, LAz);
      } else if(col >= 0 && !(collide[col].interacting)) {
        interactingObj = col;
        glutTimerFunc(TIMER, interact, 0);
      }
      break;
    case 's':
      col = willCollide(Eyex + moveInc * wx, Eyey, Eyez + moveInc * wz);
      if(col == -1) {
          Eyex += moveInc * (wx);
          Eyez += moveInc * (wz);
          LAx += moveInc * (wx);
          LAz += moveInc * (wz);
          Eye = glm::vec3(Eyex, 0, Eyez);
          LA = glm::vec3(LAx, LAy, LAz);
      } else if(col >= 0 && !collide[col].interacting) {
        interactingObj = col;
        glutTimerFunc(TIMER, interact, 0);
      }
      break;
    case 'a':
      col = willCollide(Eyex - moveInc * ux, Eyey, Eyez - moveInc * uz);
      if(col == -1) {
          Eyex -= moveInc * (ux);
          Eyez -= moveInc * (uz);
          LAx -= moveInc * (ux);
          LAz -= moveInc * (uz);
          Eye = glm::vec3(Eyex, 0, Eyez);
          LA = glm::vec3(LAx, LAy, LAz);
      } else if(col >= 0 && !collide[col].interacting) {
        interactingObj = col;
        glutTimerFunc(TIMER, interact, 0);
      }
      break;
    case 'd':
      col = willCollide(Eyex + moveInc * ux, Eyey, Eyez + moveInc * uz);
      if(col == -1) {
          Eyex += moveInc * (ux);
          Eyez += moveInc * (uz);
          LAx += moveInc * (ux);
          LAz += moveInc * (uz);
          Eye = glm::vec3(Eyex, 0, Eyez);
          LA = glm::vec3(LAx, LAy, LAz);
      } else if(col >= 0 && !collide[col].interacting) {
        interactingObj = col;
        glutTimerFunc(TIMER, interact, 0);
      }
      break;
    case 'i':
      g_Yangle += 1;
      break;
    case 'k':
      g_Yangle -= 1;
      break;
    case 'r':
      g_angle = 0;
      g_Yangle = 0;
      g_Camtrans = -2;
      break;
    case 'q': case 'Q' :
      exit( EXIT_SUCCESS );
      break;
  }
  glutPostRedisplay();
}

static void timer(int value) {
  if (g_timerTrans >= 4) {
    g_dir = 0;
  } else if(g_timerTrans <= 0) {
    g_dir = 1;
  }

  if(g_dir == 1) {
    g_timerTrans += .02;
  } else {
    g_timerTrans -= .02;
  }

  glutPostRedisplay();
  glutTimerFunc(TIMER, timer, 0);
}

int main( int argc, char *argv[] )
{
   	glutInit( &argc, argv );
   	glutInitWindowPosition( 20, 20 );
   	glutInitWindowSize( 400, 400 );
   	glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
   	glutCreateWindow("My Fragment shader");
    
    srand(time(NULL));
   	glutReshapeFunc( ReshapeGL );
   	glutDisplayFunc( Draw );
	glutKeyboardFunc( keyboard );
    glutMouseFunc( mouse );
    glutMotionFunc( mouseMove );
    glutTimerFunc(TIMER, timer, 0);
   	Initialize();
	
	//test the openGL version
	getGLversion();
	//install the shader
	if (!InstallShader(textFileRead((char *)"Lab7_vert.glsl"), textFileRead((char *)"Lab7_frag.glsl"))) {
		printf("Error installing shader!\n");
		return 0;
	}
		
	InitGeom();
    SetMaterial(0);
  	glutMainLoop();
   	return 0;
}
